#pragma once

/** DO NOT INCLUDE DIRECTLY - should be included via board_definition.h */

#define CORE_SAME51
#define CORE_SAM

#include "sam.h"

/*
***********************************************************************************************************
* General
*/
#define BOARD_MAX_DIGITAL_PINS 54 //digital pins +1
#define BOARD_MAX_IO_PINS  58 //digital pins + analog channels + 1

#define COMPARE_TYPE uint16_t
#define SERIAL_BUFFER_SIZE 257 //Size of the serial buffer used by new comms protocol. Additional 1 byte is for flag
#define FPU_MAX_SIZE 32 //Size of the FPU buffer. 0 means no FPU.
#ifdef USE_SPI_EEPROM
  #define EEPROM_LIB_H "src/SPIAsEEPROM/SPIAsEEPROM.h"
  typedef uint16_t eeprom_address_t;
  #include EEPROM_LIB_H
  SPIClass SPI_for_flash = SPI; //SPI1_MOSI, SPI1_MISO, SPI1_SCK

  EEPROM_Emulation_Config EmulatedEEPROMMconfig{255UL, 4096UL, 31, 0x00100000UL};
  SPI_EEPROM_Class EEPROM(EmulatedEEPROMMconfig, SPIconfig);
#else
  #define EEPROM_LIB_H "src/FlashStorage/FlashAsEEPROM.h"
  typedef uint16_t eeprom_address_t;
#endif
#define RTC_LIB_H "TimeLib.h"

#define pinIsReserved(pin)  ( ((pin) == 0) ) //Forbidden pins like USB on other boards

//Additional analog pins (These won't work without other changes)
#define PIN_A6               (8ul)
#define PIN_A7               (9ul)
#define PIN_A8               (10ul)
#define PIN_A9               (11ul)
#define PIN_A13               (9ul)
#define PIN_A14               (9ul)
#define PIN_A15               (9ul)

static const uint8_t A7  = PIN_A7;
static const uint8_t A8  = PIN_A8;
static const uint8_t A9  = PIN_A9;
static const uint8_t A13  = PIN_A13;
static const uint8_t A14  = PIN_A14;
static const uint8_t A15  = PIN_A15;

/*
***********************************************************************************************************
* Schedules
*/
#define INJ_CHANNELS 8
#define IGN_CHANNELS 8
  
//See : https://electronics.stackexchange.com/questions/325159/the-value-of-the-tcc-counter-on-an-atsam-controller-always-reads-as-zero
// SAME512 Timer channel list: https://user-images.githubusercontent.com/11770912/62131781-2e150b80-b31f-11e9-9970-9a6c2356a17c.png
#define FUEL1_COUNTER TCC0->COUNT.reg
#define FUEL2_COUNTER TCC0->COUNT.reg
#define FUEL3_COUNTER TCC0->COUNT.reg
#define FUEL4_COUNTER TCC0->COUNT.reg
//The below are NOT YET RIGHT!
#define FUEL5_COUNTER TCC1->COUNT.reg
#define FUEL6_COUNTER TCC1->COUNT.reg
#define FUEL7_COUNTER TCC1->COUNT.reg
#define FUEL8_COUNTER TCC1->COUNT.reg

#define IGN1_COUNTER  TCC1->COUNT.reg
#define IGN2_COUNTER  TCC1->COUNT.reg
#define IGN3_COUNTER  TCC2->COUNT.reg
#define IGN4_COUNTER  TCC2->COUNT.reg
//The below are NOT YET RIGHT!
#define IGN5_COUNTER  TCC1->COUNT.reg
#define IGN6_COUNTER  TCC1->COUNT.reg
#define IGN7_COUNTER  TCC2->COUNT.reg
#define IGN8_COUNTER  TCC2->COUNT.reg

#define FUEL1_COMPARE TCC0->CC[0].bit.CC
#define FUEL2_COMPARE TCC0->CC[1].bit.CC
#define FUEL3_COMPARE TCC0->CC[2].bit.CC
#define FUEL4_COMPARE TCC0->CC[3].bit.CC
//The below are NOT YET RIGHT!
#define FUEL5_COMPARE TCC1->CC[0].bit.CC
#define FUEL6_COMPARE TCC1->CC[1].bit.CC
#define FUEL7_COMPARE TCC1->CC[2].bit.CC
#define FUEL8_COMPARE TCC1->CC[3].bit.CC

#define IGN1_COMPARE  TCC1->CC[0].bit.CC
#define IGN2_COMPARE  TCC1->CC[1].bit.CC
#define IGN3_COMPARE  TCC2->CC[0].bit.CC
#define IGN4_COMPARE  TCC2->CC[1].bit.CC
//The below are NOT YET RIGHT!
#define IGN5_COMPARE  TCC1->CC[0].bit.CC
#define IGN6_COMPARE  TCC1->CC[1].bit.CC
#define IGN7_COMPARE  TCC2->CC[0].bit.CC
#define IGN8_COMPARE  TCC2->CC[1].bit.CC

static inline void FUEL1_TIMER_ENABLE(void) { TCC0->INTENSET.bit.MC0 = 0x1; }
static inline void FUEL2_TIMER_ENABLE(void) { TCC0->INTENSET.bit.MC1 = 0x1; }
static inline void FUEL3_TIMER_ENABLE(void) { TCC0->INTENSET.bit.MC2 = 0x1; }
static inline void FUEL4_TIMER_ENABLE(void) { TCC0->INTENSET.bit.MC3 = 0x1; }
  //The below are NOT YET RIGHT!
static inline void FUEL5_TIMER_ENABLE(void) { TCC0->INTENSET.bit.MC0 = 0x1; }
static inline void FUEL6_TIMER_ENABLE(void) { TCC0->INTENSET.bit.MC1 = 0x1; }
static inline void FUEL7_TIMER_ENABLE(void) { TCC0->INTENSET.bit.MC2 = 0x1; }
static inline void FUEL8_TIMER_ENABLE(void) { TCC0->INTENSET.bit.MC3 = 0x1; }

static inline void FUEL1_TIMER_DISABLE(void) { TCC0->INTENSET.bit.MC0 = 0x0; }
static inline void FUEL2_TIMER_DISABLE(void) { TCC0->INTENSET.bit.MC0 = 0x0; }
static inline void FUEL3_TIMER_DISABLE(void) { TCC0->INTENSET.bit.MC0 = 0x0; }
static inline void FUEL4_TIMER_DISABLE(void) { TCC0->INTENSET.bit.MC0 = 0x0; }
  //The below are NOT YET RIGHT!
static inline void FUEL5_TIMER_DISABLE(void) { TCC0->INTENSET.bit.MC0 = 0x0; }
static inline void FUEL6_TIMER_DISABLE(void) { TCC0->INTENSET.bit.MC0 = 0x0; }
static inline void FUEL7_TIMER_DISABLE(void) { TCC0->INTENSET.bit.MC0 = 0x0; }
static inline void FUEL9_TIMER_DISABLE(void) { TCC0->INTENSET.bit.MC0 = 0x0; }

static inline void IGN1_TIMER_ENABLE(void) { TCC1->INTENSET.bit.MC0 = 0x1; }
static inline void IGN2_TIMER_ENABLE(void) { TCC1->INTENSET.bit.MC1 = 0x1; }
static inline void IGN3_TIMER_ENABLE(void) { TCC2->INTENSET.bit.MC0 = 0x1; }
static inline void IGN4_TIMER_ENABLE(void) { TCC2->INTENSET.bit.MC1 = 0x1; }
//The below are NOT YET RIGHT!
static inline void IGN5_TIMER_ENABLE(void) { TCC1->INTENSET.bit.MC0 = 0x1; }
static inline void IGN6_TIMER_ENABLE(void) { TCC1->INTENSET.bit.MC1 = 0x1; }
static inline void IGN7_TIMER_ENABLE(void) { TCC2->INTENSET.bit.MC0 = 0x1; }
static inline void IGN8_TIMER_ENABLE(void) { TCC2->INTENSET.bit.MC1 = 0x1; }

static inline void IGN1_TIMER_DISABLE(void) { TCC1->INTENSET.bit.MC0 = 0x0; }
static inline void IGN2_TIMER_DISABLE(void) { TCC1->INTENSET.bit.MC1 = 0x0; }
static inline void IGN3_TIMER_DISABLE(void) { TCC2->INTENSET.bit.MC0 = 0x0; }
static inline void IGN4_TIMER_DISABLE(void) { TCC2->INTENSET.bit.MC1 = 0x0; }
//The below are NOT YET RIGHT!
static inline void IGN5_TIMER_DISABLE(void) { TCC1->INTENSET.bit.MC0 = 0x0; }
static inline void IGN6_TIMER_DISABLE(void) { TCC1->INTENSET.bit.MC1 = 0x0; }
static inline void IGN7_TIMER_DISABLE(void) { TCC2->INTENSET.bit.MC0 = 0x0; }
static inline void IGN8_TIMER_DISABLE(void) { TCC2->INTENSET.bit.MC1 = 0x0; }

#define MAX_TIMER_PERIOD 139808 // 2.13333333uS * 65535
#define MAX_TIMER_PERIOD_SLOW 139808
#define uS_TO_TIMER_COMPARE(uS) (((uS) * 15) >> 5) //Converts a given number of uS into the required number of timer ticks until that time has passed.
//Hack compatibility with AVR timers that run at different speeds
#define uS_TO_TIMER_COMPARE_SLOW(uS) (((uS) * 15) >> 5)

/*
***********************************************************************************************************
* Auxiliaries
*/
//Uses the 2nd TC
//The 2nd TC is referred to as TC4
#define ENABLE_BOOST_TIMER()  TC4->COUNT16.INTENSET.bit.MC0 = 0x1    // Enable match interrupts on compare channel 0 
#define DISABLE_BOOST_TIMER() TC4->COUNT16.INTENSET.bit.MC0 = 0x0

#define ENABLE_VVT_TIMER()    TC4->COUNT16.INTENSET.bit.MC1 = 0x1 
#define DISABLE_VVT_TIMER()   TC4->COUNT16.INTENSET.bit.MC1 = 0x0

#define BOOST_TIMER_COMPARE   TC4->COUNT16.CC[0].reg
#define BOOST_TIMER_COUNTER   TC4->COUNT16.COUNT.bit.COUNT
#define VVT_TIMER_COMPARE     TC4->COUNT16.CC[1].reg
#define VVT_TIMER_COUNTER     TC4->COUNT16.COUNT.bit.COUNT

/*
***********************************************************************************************************
* Idle
*/
//3rd TC is aliased as TC5
#define IDLE_COUNTER TC5->COUNT16.COUNT.bit.COUNT
#define IDLE_COMPARE TC5->COUNT16.CC[0].reg

#define IDLE_TIMER_ENABLE() TC5->COUNT16.INTENSET.bit.MC0 = 0x1
#define IDLE_TIMER_DISABLE() TC5->COUNT16.INTENSET.bit.MC0 = 0x0

/*
***********************************************************************************************************
* CAN / Second serial
*/
Uart secondarySerial (&sercom3, 0, 1, SERCOM_RX_PAD_1, UART_TX_PAD_0);
